NexusPi Git Node
tests/lora_test.py 20ec0b4ee3f3e7a8b3c8d00dcdcd5afdcf2bc840 (20ec0b4e) Text, 21.98 KB
T8b949e"""
RTNode LoRa integration test suite.
FIREWALL_MODE architecture note
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
The RTNode runs in FIREWALL_MODE, which means serial_write() is a
compile-time no-op (Utilities.h:#ifdef FIREWALL_MODE … return;).
No KISS frame responses will ever arrive from the RTNode. All
RTNode self-tests therefore parse the device's ASCII RNS debug log
output via KissSerial.wait_for_log_line() and .log_lines.
The RNode probe IS a standard KISS TNC and responds normally.
Test categories
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
CATEGORY 1 — RTNode alive tests (RTNode serial log, no RNode needed)
Verifies the device is running, RNS is active, and no error-level
log entries appear during a quiet observation window.
CATEGORY 2 — LoRa receive path (RNode → RTNode)
RNode sends a KISS DATA packet. We verify the RTNode's RNS stack
logs new activity, indicating the LoRa packet was received and
handed to the Reticulum transport layer.
CATEGORY 3 — LoRa transmit path (RTNode → RNode)
RTNode periodically transmits RNS announces and transport packets
over LoRa. The RNode (in promiscuous mode) watches for any
inbound LoRa packet.
Quick start
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
cd tests
# Self-tests only (no RNode):
pytest lora_test.py --rtnode-port /dev/cu.usbmodem114401 -v
# Full suite:
pytest lora_test.py \\
--rtnode-port /dev/cu.usbmodem114401 \\
--rnode-port /dev/cu.usbmodem11201 \\
--lora-freq 869525000 \\
--lora-bw 250000 \\
--lora-sf 8 \\
--lora-cr 5 \\
-v
"""
Tff7b72import T7ee787threading
Tff7b72import T7ee787time
Tff7b72import T7ee787pytest
Tff7b72from T7ee787kiss_serial Tff7b72import Tb4b4b4(
Te6edf3CMD_DATATb4b4b4,
Te6edf3CMD_ERRORTb4b4b4,
Te6edf3KissFrameTb4b4b4,
Te6edf3KissSerialTb4b4b4,
Te6edf3RadioConfigTb4b4b4,
Tb4b4b4)
T8b949e# ── helpers ───────────────────────────────────────────────────────────────────
Tff7b72def Td2a8ff_requires_rnodeTb4b4b4(Te6edf3rnodeTb4b4b4: Ta5d6ff"Ta5d6ffKissSerial | NoneTa5d6ff"Tb4b4b4) Tff7b72-Tff7b72> Tff7b72NoneTb4b4b4:
Tff7b72if Te6edf3rnode Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3pytestTff7b72.Td2a8ffskipTb4b4b4(Ta5d6ff"Ta5d6ffRequires --rnode-port (no RNode probe attached)Ta5d6ff"Tb4b4b4)
T8b949e# ─────────────────────────────────────────────────────────────────────────────
T8b949e# CATEGORY 1 — RTNode alive tests
T8b949e# ─────────────────────────────────────────────────────────────────────────────
Tff7b72class T56d364TestRTNodeAliveTb4b4b4:
T8b949e"""
RTNode self-tests that require only the RTNode serial port.
In FIREWALL_MODE the serial port carries ASCII RNS log lines only.
These tests parse that output rather than KISS frames.
"""
Tff7b72def Td2a8fftest_aliveTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3rtnodeTb4b4b4: Te6edf3KissSerialTb4b4b4)Tb4b4b4:
T8b949e"""
RTNode produces ASCII log output — confirms the firmware is running
and the USB CDC serial connection is healthy.
We send a CMD_DETECT query (serial_callback processes the bytes even
though the KISS response is suppressed) to trigger RNS activity, then
wait up to 10 s for any log line to appear.
"""
Te6edf3rtnodeTff7b72.Td2a8ffquery_detectTb4b4b4(Tb4b4b4)
Te6edf3line Tff7b72= Te6edf3rtnodeTff7b72.Td2a8ffwait_for_log_lineTb4b4b4(Ta5d6ff"Ta5d6ff"Tb4b4b4, Te6edf3timeoutTff7b72=T79c0ff10.0Tb4b4b4)
Tff7b72assert Te6edf3line Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4, Tb4b4b4(
Ta5d6ff"Ta5d6ffNo ASCII log output from RTNode within 10 s after CMD_DETECT.Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff Check:Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 1. --rtnode-port points to the Heltec V4 running FIREWALL_MODETffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 2. The device is powered and the USB cable is data-capableTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 3. The firmware was compiled with ARDUINO_USB_CDC_ON_BOOT=1Ta5d6ff"
Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Tffea00\nTa5d6ff First log line: Tffd700{Te6edf3lineTb4b4b4[Tb4b4b4:T79c0ff100Tb4b4b4]Tffd700!r}Ta5d6ff"Tb4b4b4)
Tff7b72def Td2a8fftest_rns_activeTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3rtnodeTb4b4b4: Te6edf3KissSerialTb4b4b4)Tb4b4b4:
T8b949e"""
RNS stack is running and producing verbose log output.
Looks for a [VRB] VERBOSE or [TRC] TRACE log entry — the format
that the RNS heap-telemetry logger and packet handlers emit.
"""
T8b949e# Trigger activity so the RNS loop produces logs
Te6edf3rtnodeTff7b72.Td2a8ffquery_detectTb4b4b4(Tb4b4b4)
Te6edf3rtnodeTff7b72.Td2a8ffquery_radio_stateTb4b4b4(Tb4b4b4)
Te6edf3line Tff7b72= Te6edf3rtnodeTff7b72.Td2a8ffwait_for_log_lineTb4b4b4(Ta5d6ff"Ta5d6ff[VRB]Ta5d6ff"Tb4b4b4, Te6edf3timeoutTff7b72=T79c0ff10.0Tb4b4b4)
Tff7b72if Te6edf3line Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3line Tff7b72= Te6edf3rtnodeTff7b72.Td2a8ffwait_for_log_lineTb4b4b4(Ta5d6ff"Ta5d6ff[TRC]Ta5d6ff"Tb4b4b4, Te6edf3timeoutTff7b72=T79c0ff5.0Tb4b4b4)
Tff7b72if Te6edf3line Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3line Tff7b72= Te6edf3rtnodeTff7b72.Td2a8ffwait_for_log_lineTb4b4b4(Ta5d6ff"Ta5d6ffRNSTa5d6ff"Tb4b4b4, Te6edf3timeoutTff7b72=T79c0ff5.0Tb4b4b4)
Tff7b72assert Te6edf3line Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4, Tb4b4b4(
Ta5d6ff"Ta5d6ffNo RNS verbose log output detected within 20 s.Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff Expected lines containing Ta5d6ff'Ta5d6ff[VRB]Ta5d6ff'Ta5d6ff, Ta5d6ff'Ta5d6ff[TRC]Ta5d6ff'Ta5d6ff, or Ta5d6ff'Ta5d6ffRNSTa5d6ff'Ta5d6ff.Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff Ensure the firmware was compiled with HAS_RNS and the RNS Ta5d6ff"
Ta5d6ff"Ta5d6fflog level is set to LOG_VERBOSE or higher.Ta5d6ff"
Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Tffea00\nTa5d6ff RNS log sample: Tffd700{Te6edf3lineTb4b4b4[Tb4b4b4:T79c0ff100Tb4b4b4]Tffd700!r}Ta5d6ff"Tb4b4b4)
Tff7b72def Td2a8fftest_no_error_logsTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3rtnodeTb4b4b4: Te6edf3KissSerialTb4b4b4)Tb4b4b4:
T8b949e"""
No ERROR or CRITICAL log lines during a 5 s observation window.
[ERR] lines indicate hardware faults such as SX126x SPI errors,
EEPROM lock failures, or RNS stack exceptions. [CRT] lines are
fatal failures.
"""
Te6edf3error_linesTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Tff7b72def Td2a8ff_captureTb4b4b4(Te6edf3lineTb4b4b4: Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tff7b72NoneTb4b4b4:
Tff7b72if Ta5d6ff"Ta5d6ff[ERR]Ta5d6ff" Tff7b72in Te6edf3line Tff7b72or Ta5d6ff"Ta5d6ff[CRT]Ta5d6ff" Tff7b72in Te6edf3lineTb4b4b4:
Te6edf3error_linesTff7b72.Td2a8ffappendTb4b4b4(Te6edf3lineTb4b4b4)
Te6edf3rtnodeTff7b72.Td2a8ffon_log_lineTb4b4b4(Te6edf3_captureTb4b4b4)
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff5.0Tb4b4b4)
Tff7b72tryTb4b4b4:
Te6edf3rtnodeTff7b72.Td2a8ff_log_callbacksTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3_captureTb4b4b4)
Tff7b72except Tf85149ValueErrorTb4b4b4:
Tff7b72pass
Tff7b72if Te6edf3error_linesTb4b4b4:
Te6edf3formatted Tff7b72= Ta5d6ff"Tffea00\nTa5d6ff"Tff7b72.Td2a8ffjoinTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Tffd700{Te6edf3lTffd700}Ta5d6ff" Tff7b72for Te6edf3l Tff7b72in Te6edf3error_linesTb4b4b4[Tb4b4b4:T79c0ff10Tb4b4b4]Tb4b4b4)
Te6edf3pytestTff7b72.Td2a8fffailTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffError-level log lines detected from RTNode:Tffea00\nTffd700{Te6edf3formattedTffd700}Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff [ERR] often indicates ERROR_INITRADIO (SX126x SPI problem), Ta5d6ff"
Ta5d6ff"Ta5d6ffTX failure, or EEPROM lock. Check hardware connections.Ta5d6ff"
Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Tffea00\nTa5d6ff No [ERR] or [CRT] lines in 5 s observation windowTa5d6ff"Tb4b4b4)
Tff7b72def Td2a8fftest_channel_configTb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3rtnodeTb4b4b4: Te6edf3KissSerialTb4b4b4,
Te6edf3channel_configTb4b4b4: Te6edf3RadioConfigTb4b4b4,
Tb4b4b4)Tb4b4b4:
T8b949e"""
Verify that the RTNode's active channel matches the test parameters.
The updated firmware emits ``[Boundary] LoRa: freq=... bw=... sf=...
cr=... txp=...`` immediately after loading its EEPROM config. If
this line is present in the RTNode's recent log (i.e. the device
booted while the test session was running), we parse it and compare
to the CLI channel parameters.
If the line is absent (device booted before the test session), the
test is skipped with a hint to reflash or restart the RTNode so we
can capture the startup log.
"""
T8b949e# Look for the startup channel log in recently received lines
Te6edf3boundary_lineTb4b4b4: Tffa657str Tff7b72| Tff7b72None Tff7b72= Tff7b72None
Tff7b72for Te6edf3lineTb4b4b4, Te6edf3_ts Tff7b72in Te6edf3rtnodeTff7b72.Td2a8fflog_linesTb4b4b4:
Tff7b72if Ta5d6ff"Ta5d6ff[Boundary] LoRa:Ta5d6ff" Tff7b72in Te6edf3lineTb4b4b4:
Te6edf3boundary_line Tff7b72= Te6edf3line
Tff7b72break
Tff7b72if Te6edf3boundary_line Tff7b72is Tff7b72NoneTb4b4b4:
T8b949e# Also wait a short time in case we just connected mid-boot
Te6edf3boundary_line Tff7b72= Te6edf3rtnodeTff7b72.Td2a8ffwait_for_log_lineTb4b4b4(Ta5d6ff"Ta5d6ff[Boundary] LoRa:Ta5d6ff"Tb4b4b4, Te6edf3timeoutTff7b72=T79c0ff3.0Tb4b4b4)
Tff7b72if Te6edf3boundary_line Tff7b72is Tff7b72NoneTb4b4b4:
Te6edf3pytestTff7b72.Td2a8ffskipTb4b4b4(
Ta5d6ff"Ta5d6ffRTNode did not emit Ta5d6ff'Ta5d6ff[Boundary] LoRa:Ta5d6ff'Ta5d6ff during this session.Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff The device booted before the test run started.Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff To verify channel: reset the RTNode, then re-run the tests.Ta5d6ff"
Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Tffea00\nTa5d6ff RTNode startup channel line: Tffd700{Te6edf3boundary_lineTff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tffd700!r}Ta5d6ff"Tb4b4b4)
T8b949e# Parse: [Boundary] LoRa: freq=869525000 bw=250000 sf=8 cr=5 txp=14
Tff7b72import T7ee787re
Te6edf3m Tff7b72= Te6edf3reTff7b72.Td2a8ffsearchTb4b4b4(
Ta5d6ffrTa5d6ff"Ta5d6fffreq=(Ta5d6ff\Ta5d6ffd+)Ta5d6ff\Ta5d6ffs+bw=(Ta5d6ff\Ta5d6ffd+)Ta5d6ff\Ta5d6ffs+sf=(Ta5d6ff\Ta5d6ffd+)Ta5d6ff\Ta5d6ffs+cr=(Ta5d6ff\Ta5d6ffd+)Ta5d6ff\Ta5d6ffs+txp=(Ta5d6ff\Ta5d6ffd+)Ta5d6ff"Tb4b4b4,
Te6edf3boundary_lineTb4b4b4,
Tb4b4b4)
Tff7b72assert Te6edf3m Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4, Tb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffCould not parse channel values from: Tffd700{Te6edf3boundary_lineTffd700!r}Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff Expected format: freq=N bw=N sf=N cr=N txp=NTa5d6ff"
Tb4b4b4)
Te6edf3rtnode_freq Tff7b72= Tffa657intTb4b4b4(Te6edf3mTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff1Tb4b4b4)Tb4b4b4)
Te6edf3rtnode_bw Tff7b72= Tffa657intTb4b4b4(Te6edf3mTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff2Tb4b4b4)Tb4b4b4)
Te6edf3rtnode_sf Tff7b72= Tffa657intTb4b4b4(Te6edf3mTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff3Tb4b4b4)Tb4b4b4)
Te6edf3rtnode_cr Tff7b72= Tffa657intTb4b4b4(Te6edf3mTff7b72.Td2a8ffgroupTb4b4b4(T79c0ff4Tb4b4b4)Tb4b4b4)
Tff7b72assert Te6edf3rtnode_freq Tff7b72== Te6edf3channel_configTff7b72.Td2a8fffrequencyTb4b4b4, Tb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffRTNode freq Tffd700{Te6edf3rtnode_freqTffd700}Ta5d6ff Hz ≠ test --lora-freq Tffd700{Te6edf3channel_configTff7b72.Td2a8fffrequencyTffd700}Ta5d6ff HzTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff Update --lora-freq to match the RTNodeTa5d6ff'Ta5d6ffs EEPROM config, orTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff change the channel via the RTNode web portal.Ta5d6ff"
Tb4b4b4)
Tff7b72assert Te6edf3rtnode_bw Tff7b72== Te6edf3channel_configTff7b72.Td2a8ffbandwidthTb4b4b4, Tb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffRTNode bw Tffd700{Te6edf3rtnode_bwTffd700}Ta5d6ff Hz ≠ test --lora-bw Tffd700{Te6edf3channel_configTff7b72.Td2a8ffbandwidthTffd700}Ta5d6ff HzTa5d6ff"
Tb4b4b4)
Tff7b72assert Te6edf3rtnode_sf Tff7b72== Te6edf3channel_configTff7b72.Td2a8ffsfTb4b4b4, Tb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffRTNode sf Tffd700{Te6edf3rtnode_sfTffd700}Ta5d6ff ≠ test --lora-sf Tffd700{Te6edf3channel_configTff7b72.Td2a8ffsfTffd700}Ta5d6ff"
Tb4b4b4)
Tff7b72assert Te6edf3rtnode_cr Tff7b72== Te6edf3channel_configTff7b72.Td2a8ffcrTb4b4b4, Tb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffRTNode cr Tffd700{Te6edf3rtnode_crTffd700}Ta5d6ff ≠ test --lora-cr Tffd700{Te6edf3channel_configTff7b72.Td2a8ffcrTffd700}Ta5d6ff"
Tb4b4b4)
Tffa657printTb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ff Channel matches: freq=Tffd700{Te6edf3rtnode_freqTffd700}Ta5d6ff Hz, bw=Tffd700{Te6edf3rtnode_bwTffd700}Ta5d6ff Hz, Ta5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ffsf=Tffd700{Te6edf3rtnode_sfTffd700}Ta5d6ff, cr=Tffd700{Te6edf3rtnode_crTffd700}Ta5d6ff"
Tb4b4b4)
T8b949e# ─────────────────────────────────────────────────────────────────────────────
T8b949e# CATEGORY 2 — LoRa receive path (RNode TX → RTNode RX)
T8b949e# ─────────────────────────────────────────────────────────────────────────────
Tff7b72class T56d364TestLoRaReceiveTb4b4b4:
T8b949e"""
Requires an attached RNode probe (--rnode-port).
The RNode transmits a test packet on the configured channel. The
firmware now emits ``[VRB] [LoRa] RX N bytes`` at LOG_VERBOSE level
whenever a LoRa frame arrives at the physical layer. We wait for
exactly that log pattern — any match is a definitive confirmation
that the RTNode received the packet over the air.
Previous tests matched *any* log line which was a false positive
because the periodic ``[HEAP-TEL] boundary:`` telemetry fires every
~2 s regardless of LoRa activity.
"""
Tff7b72def Td2a8fftest_rnode_tx_rtnode_receivesTb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3rtnodeTb4b4b4: Te6edf3KissSerialTb4b4b4,
Te6edf3rnodeTb4b4b4: Ta5d6ff"Ta5d6ffKissSerial | NoneTa5d6ff"Tb4b4b4,
Te6edf3channel_configTb4b4b4: Te6edf3RadioConfigTb4b4b4,
Te6edf3tx_payloadTb4b4b4: Tffa657bytesTb4b4b4,
Te6edf3rx_timeoutTb4b4b4: Tffa657floatTb4b4b4,
Tb4b4b4)Tb4b4b4:
T8b949e"""
Basic LoRa receive path.
1. RNode transmits *tx_payload* via CMD_DATA on the configured channel.
2. We wait up to *rx_timeout* seconds for the RTNode to emit
``[LoRa] RX`` in its log — the VERBOSE-level line added to
``LoRaInterface::handle_incoming`` in the firmware.
3. A match is unambiguous proof the LoRa frame was received.
Failure means the RTNode did not receive the LoRa packet.
Common causes:
- Wrong channel parameters (--lora-freq/bw/sf/cr)
- Missing antenna on either device
- RTNode radio failed to initialise (look for [ERR] in test_no_error_logs)
- Devices out of range
- Old firmware build (rebuild + reflash to get [LoRa] RX log)
"""
Te6edf3_requires_rnodeTb4b4b4(Te6edf3rnodeTb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Tffea00\nTa5d6ff Channel: Tffd700{Te6edf3channel_configTffd700}Ta5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Sending Tffd700{Te6edf3tx_payloadTffd700!r}Ta5d6ff from RNode → RTNode …Ta5d6ff"Tb4b4b4)
Te6edf3rnodeTff7b72.Td2a8ffsend_packetTb4b4b4(Te6edf3tx_payloadTb4b4b4)
Te6edf3line Tff7b72= Te6edf3rtnodeTff7b72.Td2a8ffwait_for_log_lineTb4b4b4(Ta5d6ff"Ta5d6ff[LoRa] RXTa5d6ff"Tb4b4b4, Te6edf3timeoutTff7b72=Te6edf3rx_timeoutTb4b4b4)
Tff7b72assert Te6edf3line Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4, Tb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffRTNode did not log Ta5d6ff'Ta5d6ff[LoRa] RXTa5d6ff'Ta5d6ff within Tffd700{Te6edf3rx_timeoutTffd700}Ta5d6ff s after RNode TX.Tffea00\nTa5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ff Channel: Tffd700{Te6edf3channel_configTffd700}Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff Check:Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 1. --lora-freq/bw/sf/cr match the RTNodeTa5d6ff'Ta5d6ffs EEPROM configTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff (see test_channel_config or Ta5d6ff'Ta5d6ff[Boundary] LoRa:Ta5d6ff'Ta5d6ff in startup log)Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 2. Antennas are attached to both devicesTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 3. Devices are within LoRa rangeTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 4. Firmware has the [LoRa] RX log (rebuild + reflash if not)Ta5d6ff"
Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Tffea00\nTa5d6ff RTNode logged: Tffd700{Te6edf3lineTb4b4b4[Tb4b4b4:T79c0ff100Tb4b4b4]Tffd700!r}Ta5d6ff"Tb4b4b4)
Tff7b72def Td2a8fftest_rnode_tx_rtnode_receives_multipleTb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3rtnodeTb4b4b4: Te6edf3KissSerialTb4b4b4,
Te6edf3rnodeTb4b4b4: Ta5d6ff"Ta5d6ffKissSerial | NoneTa5d6ff"Tb4b4b4,
Te6edf3channel_configTb4b4b4: Te6edf3RadioConfigTb4b4b4,
Te6edf3tx_payloadTb4b4b4: Tffa657bytesTb4b4b4,
Te6edf3rx_timeoutTb4b4b4: Tffa657floatTb4b4b4,
Tb4b4b4)Tb4b4b4:
T8b949e"""
Reliability check: send 3 packets and verify the RTNode logs
``[LoRa] RX`` for at least 2 of them.
A consistent receive rate of 0/3 indicates a channel mismatch or
hardware problem. Occasional misses (1/3) can indicate interference
or range issues.
"""
Te6edf3_requires_rnodeTb4b4b4(Te6edf3rnodeTb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Tffea00\nTa5d6ff Channel: Tffd700{Te6edf3channel_configTffd700}Ta5d6ff"Tb4b4b4)
Te6edf3received Tff7b72= T79c0ff0
Tff7b72for Te6edf3i Tff7b72in Tffa657rangeTb4b4b4(T79c0ff3Tb4b4b4)Tb4b4b4:
Te6edf3rnodeTff7b72.Td2a8ffsend_packetTb4b4b4(Te6edf3tx_payload Tff7b72+ Ta5d6fffTa5d6ff"Ta5d6ff #Tffd700{Te6edf3iTff7b72+T79c0ff1Tffd700}Ta5d6ff"Tff7b72.Td2a8ffencodeTb4b4b4(Tb4b4b4)Tb4b4b4)
Te6edf3line Tff7b72= Te6edf3rtnodeTff7b72.Td2a8ffwait_for_log_lineTb4b4b4(Ta5d6ff"Ta5d6ff[LoRa] RXTa5d6ff"Tb4b4b4, Te6edf3timeoutTff7b72=Te6edf3rx_timeoutTb4b4b4)
Tff7b72if Te6edf3line Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Te6edf3received Tff7b72+Tff7b72= T79c0ff1
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Packet Tffd700{Te6edf3iTff7b72+T79c0ff1Tffd700}Ta5d6ff/3: RTNode logged Ta5d6ff'Ta5d6ff[LoRa] RXTa5d6ff'Ta5d6ff ✓Ta5d6ff"Tb4b4b4)
Tff7b72elseTb4b4b4:
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Packet Tffd700{Te6edf3iTff7b72+T79c0ff1Tffd700}Ta5d6ff/3: no Ta5d6ff'Ta5d6ff[LoRa] RXTa5d6ff'Ta5d6ff in RTNode log ✗Ta5d6ff"Tb4b4b4)
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.5Tb4b4b4)
Tff7b72assert Te6edf3received Tff7b72>Tff7b72= T79c0ff2Tb4b4b4, Tb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffRTNode only logged Ta5d6ff'Ta5d6ff[LoRa] RXTa5d6ff'Ta5d6ff for Tffd700{Te6edf3receivedTffd700}Ta5d6ff/3 transmitted packets.Tffea00\nTa5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ff Channel: Tffd700{Te6edf3channel_configTffd700}Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff Expected ≥2/3. Persistent failure suggests wrong channel config.Ta5d6ff"
Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Tffea00\nTa5d6ff Receive rate: Tffd700{Te6edf3receivedTffd700}Ta5d6ff/3Ta5d6ff"Tb4b4b4)
T8b949e# ─────────────────────────────────────────────────────────────────────────────
T8b949e# CATEGORY 3 — LoRa transmit path (RTNode TX → RNode RX)
T8b949e# ─────────────────────────────────────────────────────────────────────────────
Tff7b72class T56d364TestLoRaTransmitTb4b4b4:
T8b949e"""
Requires an attached RNode probe (--rnode-port).
The RTNode's firmware emits ``[VRB] [LoRa] TX N bytes`` at
LOG_VERBOSE level every time it queues a frame for LoRa transmission.
We trigger transmission by resetting the RTNode via its serial port's
DTR/RTS lines — the resulting reboot causes the RNS transport layer to
send its startup ``probe_destination.announce()`` packet over LoRa.
The RNode in promiscuous mode simultaneously listens for any received
LoRa frame to confirm the transmission actually reached the air.
"""
Tf0883e@staticmethod
Tff7b72def Td2a8ff_reset_via_dtrTb4b4b4(Te6edf3serTb4b4b4: Ta5d6ff"Ta5d6ffserial.SerialTa5d6ff"Tb4b4b4) Tff7b72-Tff7b72> Tffa657boolTb4b4b4:
T8b949e"""
Attempt to reset the ESP32-S3 via DTR/RTS serial control lines.
Standard Arduino auto-reset sequence (works on most USB-to-UART
adapters and on the ESP32-S3 native USB CDC boot bridge):
DTR=False, RTS=True → holds RESET low
DTR=False, RTS=False → releases RESET → device boots
Returns True if the DTR attribute exists, False otherwise.
"""
Tff7b72tryTb4b4b4:
Te6edf3serTff7b72.Td2a8ffsetDTRTb4b4b4(Tff7b72FalseTb4b4b4)
Te6edf3serTff7b72.Td2a8ffsetRTSTb4b4b4(Tff7b72TrueTb4b4b4)
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.1Tb4b4b4)
Te6edf3serTff7b72.Td2a8ffsetDTRTb4b4b4(Tff7b72FalseTb4b4b4)
Te6edf3serTff7b72.Td2a8ffsetRTSTb4b4b4(Tff7b72FalseTb4b4b4)
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.1Tb4b4b4)
Tff7b72return Tff7b72True
Tff7b72except Tf85149ExceptionTb4b4b4:
Tff7b72return Tff7b72False
Tff7b72def Td2a8fftest_rnode_receives_rtnode_packetTb4b4b4(
Tff7b72selfTb4b4b4,
Te6edf3rtnodeTb4b4b4: Te6edf3KissSerialTb4b4b4,
Te6edf3rnodeTb4b4b4: Ta5d6ff"Ta5d6ffKissSerial | NoneTa5d6ff"Tb4b4b4,
Te6edf3channel_configTb4b4b4: Te6edf3RadioConfigTb4b4b4,
Te6edf3announce_timeoutTb4b4b4: Tffa657floatTb4b4b4,
Tb4b4b4)Tb4b4b4:
T8b949e"""
Verify the RTNode's LoRa transmitter is working end-to-end.
Strategy
--------
1. Reset the RTNode via DTR/RTS so its RNS stack restarts and
sends the startup ``probe_destination.announce()`` over LoRa.
2. Watch the RTNode's serial log for ``[LoRa] TXSTART`` — the
firmware log that fires inside ``transmit()`` immediately before
the SX126x packet is written, confirming actual RF transmission.
(``[LoRa] TX`` fires earlier at packet-queue time and is shown
for information only; TXSTART proves the RF actually started.)
3. Simultaneously watch the RNode (promiscuous) for any LoRa frame.
4. Both must succeed: RTNode logs TXSTART *and* RNode receives a packet.
If the DTR reset has no effect (native USB CDC on some hardware),
the test falls back to waiting the full ``announce_timeout`` for a
spontaneous transmission (e.g., a deferred announce from the RNS
jobs loop).
Failure indicates:
- RTNode LoRa TX hardware issue (check ``[ERR]`` in alive tests)
- Channel mismatch — RTNode EEPROM freq ≠ RNode config
(run ``test_channel_config`` to diagnose)
- CSMA blocking TX: check for ``[LoRa] TX BLOCKED`` messages
- announce_timeout too short; try ``--announce-timeout 300``
- Old firmware — rebuild + reflash to get ``[LoRa] TXSTART`` log
"""
Te6edf3_requires_rnodeTb4b4b4(Te6edf3rnodeTb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Tffea00\nTa5d6ff Channel: Tffd700{Te6edf3channel_configTffd700}Ta5d6ff"Tb4b4b4)
T8b949e# ── Step 1: register all listeners BEFORE triggering any reset ────
T8b949e# [LoRa] TXSTART fires when transmit() is called (actual RF start).
T8b949e# Register both the RTNode TX watcher and the RNode packet listener
T8b949e# now, before anything is triggered.
Te6edf3rnode_packetTb4b4b4: Tffa657list Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3rnode_evt Tff7b72= Te6edf3threadingTff7b72.Td2a8ffEventTb4b4b4(Tb4b4b4)
Tff7b72def Td2a8ff_bg_rnode_waitTb4b4b4(Tb4b4b4) Tff7b72-Tff7b72> Tff7b72NoneTb4b4b4:
Te6edf3result Tff7b72= Te6edf3rnodeTff7b72.Td2a8ffwait_for_packetTb4b4b4(Te6edf3timeoutTff7b72=Te6edf3announce_timeout Tff7b72+ T79c0ff30.0Tb4b4b4)
Tff7b72if Te6edf3resultTb4b4b4:
Te6edf3rnode_packetTff7b72.Td2a8ffappendTb4b4b4(Te6edf3resultTb4b4b4)
Te6edf3rnode_evtTff7b72.Td2a8ffsetTb4b4b4(Tb4b4b4)
Te6edf3txstart_linesTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4]
Te6edf3txstart_evt Tff7b72= Te6edf3threadingTff7b72.Td2a8ffEventTb4b4b4(Tb4b4b4)
Te6edf3tx_queue_linesTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4] T8b949e# [LoRa] TX (queue event, informational)
Te6edf3tx_blocked_linesTb4b4b4: Tffa657listTb4b4b4[Tffa657strTb4b4b4] Tff7b72= Tb4b4b4[Tb4b4b4] T8b949e# [LoRa] TX BLOCKED (CSMA diagnostics)
Tff7b72def Td2a8ff_tx_cbTb4b4b4(Te6edf3lineTb4b4b4: Tffa657strTb4b4b4) Tff7b72-Tff7b72> Tff7b72NoneTb4b4b4:
Tff7b72if Ta5d6ff"Ta5d6ff[LoRa] TXSTARTTa5d6ff" Tff7b72in Te6edf3line Tff7b72and Tff7b72not Te6edf3txstart_linesTb4b4b4:
Te6edf3txstart_linesTff7b72.Td2a8ffappendTb4b4b4(Te6edf3lineTb4b4b4)
Te6edf3txstart_evtTff7b72.Td2a8ffsetTb4b4b4(Tb4b4b4)
Tff7b72elif Ta5d6ff"Ta5d6ff[LoRa] TX BLOCKEDTa5d6ff" Tff7b72in Te6edf3lineTb4b4b4:
Te6edf3tx_blocked_linesTff7b72.Td2a8ffappendTb4b4b4(Te6edf3lineTb4b4b4)
Tff7b72elif Ta5d6ff"Ta5d6ff[LoRa] TX Ta5d6ff" Tff7b72in Te6edf3line Tff7b72and Tff7b72not Te6edf3txstart_lines Tff7b72and Tff7b72not Te6edf3tx_queue_linesTb4b4b4:
Te6edf3tx_queue_linesTff7b72.Td2a8ffappendTb4b4b4(Te6edf3lineTb4b4b4)
Te6edf3bg Tff7b72= Te6edf3threadingTff7b72.Td2a8ffThreadTb4b4b4(Te6edf3targetTff7b72=Te6edf3_bg_rnode_waitTb4b4b4, Te6edf3daemonTff7b72=Tff7b72TrueTb4b4b4)
Te6edf3bgTff7b72.Td2a8ffstartTb4b4b4(Tb4b4b4)
Te6edf3rtnodeTff7b72.Td2a8ffon_log_lineTb4b4b4(Te6edf3_tx_cbTb4b4b4)
Te6edf3timeTff7b72.Td2a8ffsleepTb4b4b4(T79c0ff0.1Tb4b4b4) T8b949e# let callbacks register before we trigger TX
Tff7b72tryTb4b4b4:
T8b949e# ── Step 2: attempt DTR reset to trigger startup announce ─────
Te6edf3reset_attempted Tff7b72= Tff7b72selfTff7b72.Td2a8ff_reset_via_dtrTb4b4b4(Te6edf3rtnodeTff7b72.Td2a8ff_serTb4b4b4)
Tff7b72if Te6edf3reset_attemptedTb4b4b4:
Tffa657printTb4b4b4(Ta5d6ff"Ta5d6ff DTR/RTS reset sent — waiting for RTNode to reboot …Ta5d6ff"Tb4b4b4)
Tff7b72elseTb4b4b4:
Tffa657printTb4b4b4(Ta5d6ff"Ta5d6ff DTR reset not available — waiting for spontaneous TX …Ta5d6ff"Tb4b4b4)
T8b949e# ── Step 3: wait for [LoRa] TXSTART in RTNode log ─────────────
T8b949e# TXSTART fires inside transmit() — actual SX126x write starts.
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Waiting for Ta5d6ff'Ta5d6ff[LoRa] TXSTARTTa5d6ff'Ta5d6ff in RTNode log (up to Tffd700{Te6edf3announce_timeoutTffd700}Ta5d6ff s) …Ta5d6ff"Tb4b4b4)
Te6edf3txstart_evtTff7b72.Td2a8ffwaitTb4b4b4(Te6edf3timeoutTff7b72=Te6edf3announce_timeoutTb4b4b4)
Te6edf3txstart_log Tff7b72= Te6edf3txstart_linesTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72if Te6edf3txstart_lines Tff7b72else Tff7b72None
Tff7b72if Te6edf3tx_queue_linesTb4b4b4:
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff TX queued : Tffd700{Te6edf3tx_queue_linesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Tb4b4b4:T79c0ff100Tb4b4b4]Tffd700!r}Ta5d6ff"Tb4b4b4)
Tff7b72if Te6edf3tx_blocked_linesTb4b4b4:
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff TX BLOCKED (Tffd700{Tffa657lenTb4b4b4(Te6edf3tx_blocked_linesTb4b4b4)Tffd700}Ta5d6ff times): Tffd700{Te6edf3tx_blocked_linesTb4b4b4[T79c0ff0Tb4b4b4]Tb4b4b4[Tb4b4b4:T79c0ff120Tb4b4b4]Tffd700!r}Ta5d6ff"Tb4b4b4)
Tff7b72assert Te6edf3txstart_log Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4, Tb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffRTNode did not log Ta5d6ff'Ta5d6ff[LoRa] TXSTARTTa5d6ff'Ta5d6ff within Tffd700{Te6edf3announce_timeoutTffd700}Ta5d6ff s.Tffea00\nTa5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ff Channel: Tffd700{Te6edf3channel_configTffd700}Tffea00\nTa5d6ff"
Tff7b72+ Tb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ff TX was queued (Tffd700{Te6edf3tx_queue_linesTb4b4b4[T79c0ff0Tb4b4b4]Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tffd700!r}Ta5d6ff) but CSMA blocked actual RF TX.Tffea00\nTa5d6ff"
Ta5d6fffTa5d6ff"Ta5d6ff CSMA blocks: Tffd700{Tffa657lenTb4b4b4(Te6edf3tx_blocked_linesTb4b4b4)Tffd700}Ta5d6ff × Ta5d6ff'Ta5d6ff[LoRa] TX BLOCKEDTa5d6ff'Tffea00\nTa5d6ff"
Tff7b72+ Tb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Last BLOCKED: Tffd700{Te6edf3tx_blocked_linesTb4b4b4[Tff7b72-T79c0ff1Tb4b4b4]Tff7b72.Td2a8ffstripTb4b4b4(Tb4b4b4)Tffd700!r}Tffea00\nTa5d6ff" Tff7b72if Te6edf3tx_blocked_lines Tff7b72else Ta5d6ff"Ta5d6ff"Tb4b4b4)
Tff7b72if Te6edf3tx_queue_lines Tff7b72else
Ta5d6ff"Ta5d6ff Possible causes:Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 1. DTR reset had no effect and no spontaneous TX occurredTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 2. Old firmware — rebuild + reflash to get Ta5d6ff'Ta5d6ff[LoRa] TXSTARTTa5d6ff'Ta5d6ff logTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 3. TX hardware fault (see test_no_error_logs)Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 4. Try --announce-timeout 300 if announce interval is longTffea00\nTa5d6ff"
Tb4b4b4)
Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff TXSTART : Tffd700{Te6edf3txstart_logTb4b4b4[Tb4b4b4:T79c0ff100Tb4b4b4]Tffd700!r}Ta5d6ff"Tb4b4b4)
T8b949e# ── Step 4: verify the RNode received the frame ────────────────
T8b949e# TXSTART fired — the SX126x is writing the packet. Give the
T8b949e# air-time (SF10 BW125 ≈ 1.3 s for 167 bytes) plus margin.
Te6edf3rnode_evtTff7b72.Td2a8ffwaitTb4b4b4(Te6edf3timeoutTff7b72=T79c0ff15.0Tb4b4b4)
Te6edf3result Tff7b72= Te6edf3rnode_packetTb4b4b4[T79c0ff0Tb4b4b4] Tff7b72if Te6edf3rnode_packet Tff7b72else Tff7b72None
Tff7b72finallyTb4b4b4:
Tff7b72tryTb4b4b4:
Te6edf3rtnodeTff7b72.Td2a8ff_log_callbacksTff7b72.Td2a8ffremoveTb4b4b4(Te6edf3_tx_cbTb4b4b4)
Tff7b72except Tf85149ValueErrorTb4b4b4:
Tff7b72pass
Tff7b72assert Te6edf3result Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4, Tb4b4b4(
Ta5d6ff"Ta5d6ffRTNode logged Ta5d6ff'Ta5d6ff[LoRa] TXSTARTTa5d6ff'Ta5d6ff but RNode received nothing within 15 s.Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff The SX126x started transmitting but the RNode did not decode the frame.Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff Check:Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 1. Antennas attached to both devicesTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 2. Devices within LoRa rangeTffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff 3. Channel config matches (--lora-freq/bw/sf/cr)Ta5d6ff"
Tb4b4b4)
Te6edf3dataTb4b4b4, Te6edf3rssiTb4b4b4, Te6edf3_ts Tff7b72= Te6edf3result
Te6edf3rssi_str Tff7b72= Ta5d6fffTa5d6ff"Tffd700{Te6edf3rssiTffd700}Ta5d6ff dBmTa5d6ff" Tff7b72if Te6edf3rssi Tff7b72is Tff7b72not Tff7b72None Tff7b72else Ta5d6ff"Ta5d6ffunknownTa5d6ff"
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Tffea00\nTa5d6ff RNode received Tffd700{Tffa657lenTb4b4b4(Te6edf3dataTb4b4b4)Tffd700}Ta5d6ff bytes, RSSI=Tffd700{Te6edf3rssi_strTffd700}Ta5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ff Payload (hex): Tffd700{Te6edf3dataTff7b72.Td2a8ffhexTb4b4b4(Tb4b4b4)Tb4b4b4[Tb4b4b4:T79c0ff64Tb4b4b4]Tffd700}Tffd700{Ta5d6ff'Ta5d6ff…Ta5d6ff' Tff7b72if Tffa657lenTb4b4b4(Te6edf3dataTb4b4b4) Tff7b72> T79c0ff32 Tff7b72else Ta5d6ff'Ta5d6ff'Tffd700}Ta5d6ff"Tb4b4b4)
Tff7b72assert Tffa657lenTb4b4b4(Te6edf3dataTb4b4b4) Tff7b72> T79c0ff0Tb4b4b4, Ta5d6ff"Ta5d6ffReceived empty packet (0 bytes)Ta5d6ff"
Tff7b72if Te6edf3rssi Tff7b72is Tff7b72not Tff7b72NoneTb4b4b4:
Tff7b72assert Tff7b72-T79c0ff130 Tff7b72<Tff7b72= Te6edf3rssi Tff7b72<Tff7b72= Tff7b72-T79c0ff10Tb4b4b4, Tb4b4b4(
Ta5d6fffTa5d6ff"Ta5d6ffRSSI Tffd700{Te6edf3rssiTffd700}Ta5d6ff dBm is outside the plausible range [-130, -10].Tffea00\nTa5d6ff"
Ta5d6ff"Ta5d6ff This may indicate phantom reception or a hardware issue.Ta5d6ff"
Tb4b4b4)
Served by rngit 1.4.2 - Generated in 0.04s